import { __CONFIG__, doDecode, doEncode } from "@/common";
import { UUID } from "@/utils";
import { Dialog } from "antd-mobile";
import { FetchAPI, FetchResult } from "../../serve/interfaces";
import { TemplateRender } from "../../serve/utils/common";

export const fetchHeaders = (method: 'get' | 'post' = 'get') => {
  const template = __CONFIG__?.headers || {}
  const result: Record<string, string> = {}
  Object.entries(template).forEach(([k, v]) => {
    result[k] = v && v.replace(/\$\{([\w\.]+)\}/g, (_, sign) => {
      switch (sign) {
        case 'method': return method;
        case 'timestamp': return Date.now() + '';
        case 'uuid': return UUID();
        default: return _;
      }
    })
  })
  return result
}
export const Fetch = async <F = unknown, T = unknown>(url: string, data?: F, init?: RequestInit, ignore_alert: boolean = false): Promise<T> => {
  const method = data ? "post" : "get"
  return fetch(url, {
    credentials: "include",
    headers: {
      ...fetchHeaders(method),
      "Content-Type": data instanceof FormData ? "application/x-www-form-urlencoded" : "application/json",
    },
    method,
    body: data instanceof FormData ? data : data && JSON.stringify(doEncode(data)),
    ...init,
  })
    .then(async (res) => {
      if (res.redirected) {
        location.reload();
      } else {
        let result = await res.json();
        result = doDecode(result)
        if (!result.success && result.error && !ignore_alert) {
          Dialog.alert({
            content: result.error || result.msg,
            onClose: function () {
              if (result.status === 403) {
                location.reload();
              }
            },
          });
          if (result.location) {
            location.href = TemplateRender(result.location, location)
          }
        }
        return result;
      }
    })
    .catch((e) => {
      Dialog.alert({
        content: e.toString(),
      });
    });
};

export type C<K extends FetchAPI> = K extends FetchAPI<infer T, infer F> ? {
  (body?: T): Promise<FetchResult<F>>
} : never
